﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Net_SCADA;
using Spire.Pdf;
using Spire.Pdf.Graphics;

namespace WZXC_GBL_QUERY
{
    public partial class Form_QueryBoxByDay : Form
    {
        private Size ScreenSize;
        private Label[] lbl_AxisLeft=new Label[6];
        private Label[] lbl_AxisRight=new Label[6];
        private DateTime StartTime=new DateTime();
        private DateTime EndTime=new DateTime();
        private float[,] BoxData;
        private float[,] limit=new float[2,5];
        private int[] ZoneStartIntervalMinutes;
        Ini inifile = new Ini(Application.StartupPath + @"\Settings\Curve.dat");
        private List<ZoneData> z=new List<ZoneData>();
        int Xscale=1;
        private bool isEmptyBox=true;
        private int CurveHeight=100;
        private int YAxisHeight=100;
        private List<Label> Equiplbl=new List<Label>();
        bool isLoadInterface=false;
        private DataTable BoxDetail=new DataTable();
        private  Dictionary  <int,PVMaxMin> dicZoneMaxMin= new Dictionary<int, PVMaxMin>();
        private List<KeyTime> KeyTimeForAlarm=new List<KeyTime>();
        private DataTable ProductInfoTitle = DBOperate.GetProductInfoTitle();//获取零件信息设置的标题
        //private DataTable BatchInfoTitle = DBOperate.GetBatchInfoTitle();//获取批次设置的标题信息
        List<Zone> lstzone = new List<Zone>();
        public Form_QueryBoxByDay()
        {
            InitializeComponent();
        }

        private void Form_QueryBoxByDay_Load(object sender , EventArgs e)
        {
            isLoadInterface = true;
            ScreenSize = Screen.PrimaryScreen.WorkingArea.Size;
            Show();
            SetInterface();
            LoadBoxCurveSetting();
            LoadBoxKeyTimeInterface();
            LoadBoxInfoInterface();
            isLoadInterface = false;
            ShowBox();
            foreach (var item in QueryForms.fmquery.netline.zone.Values)
            {
                if (item.svtype < 10 && item.isSV)
                    lstzone.Add(item);
            }
            print.PrintPage += Print_PrintPage;
        }



        private void SetInterface()
        {
            pnl_BoxQuery.Size = new Size(ScreenSize.Width , ScreenSize.Height - 60);
            grdProduct.Size = lvKeyTime.Size = new Size((ScreenSize.Width - 15) / 2 , 335);
            lbl_ListTitle.Top = lbl_BoxInfoTitle.Top = 2;
            lbl_ListTitle.Left = 5;
            grdProduct.Location = new Point(5 , lbl_ListTitle.Height + lbl_ListTitle.Top + 2);
            lvKeyTime.Location = new Point(lvKeyTime.Width + 10 , lbl_ListTitle.Height + lbl_ListTitle.Top + 2);
            lbl_BoxInfoTitle.Left = lvKeyTime.Left;
            lbl_ListTitle.Text = dtp_Day.Value.ToString("yyyy年MM月dd日 生产信息");
            pnl_Curve.Location = new Point(0 , grdProduct.Top + grdProduct.Height + 5);
            pnl_Curve.Size = new Size(ScreenSize.Width , ScreenSize.Height - pnl_BoxInfo.Height - grdProduct.Top - grdProduct.Height - 5);
            pic_Curve.Location = new Point(pic_AxisL.Width , 0);
            pic_Curve.Size = new Size(pnl_Curve.Width - pic_AxisL.Width - pic_AxisR.Width , pnl_Curve.Height);
            lbl_TempTitle.Parent = pic_AxisL;
            lbl_CPTitle.Parent = pic_AxisR;
            lbl_CPTitle.Location = lbl_TempTitle.Location = new Point(5 , 30);

            dtp_Day.Location = new Point(ScreenSize.Width - dtp_Day.Width  - 5 , 1);


            for (int i = 0 ; i < lbl_AxisLeft.Length ; i++)
            {
                pic_AxisL.Controls.Add(lbl_AxisLeft[i] = new Label()
                {
                    Size = new Size(pic_AxisL.Width , 16) ,
                    TextAlign = ContentAlignment.TopRight
                });
                pic_AxisR.Controls.Add(lbl_AxisRight[i] = new Label()
                {
                    Size = new Size(pic_AxisR.Width , 16) ,
                    TextAlign = ContentAlignment.TopLeft
                });
            }

            gp_LoadData.Location = new Point((pnl_Curve.Width - gp_LoadData.Width) / 2 , (pnl_Curve.Height - gp_LoadData.Height) / 2);
            pnl_Print.Location = new Point(this.Width / 2 - pnl_Print.Width / 2, this.Height / 2 - pnl_Print.Height / 2);
        }
        private void LoadBoxCurveSetting()
        {
            //显示物料box的设置
            for (int i = 0 ; i < 5 ; i++)
            {
                limit[0 , i] = Convert.ToSingle("0" + inifile.ReadValue("BoxCurve" + i , "Min"));
                limit[1 , i] = Convert.ToSingle("0" + inifile.ReadValue("BoxCurve" + i , "Max"));
                z.Add(new ZoneData());
                z[i].Width = (ScreenSize.Width - 350) / 3;
                z[i].Location = new Point((ScreenSize.Width - 350) / 3 * (i/2) , 25*(i % 2));
                string unit=inifile.ReadValue("BoxCurve" + i , "Unit");
                z[i].lbl_Name.Text = inifile.ReadValue("BoxCurve" + i , "Name") + (unit==""?"": "(" + unit + ")");
                z[i].chk_ShowItem.Checked = inifile.ReadValue("BoxCurve" + i , "Selected") == "1" ? true : false;
                z[i].lbl_Color.BackColor = Color.FromArgb(Convert.ToInt32(inifile.ReadValue("BoxCurve" + i , "Color")));
                z[i].CheckSelect += ZoneData_CheckSelect;
                z[i].ColorSelect += ZoneData_ColorSelect;
                z[i].Tag = i;
                pnl_BoxInfo.Controls.Add(z.Last());
            }
            z[4].lbl_Value.Text = "";

        }

        private void ZoneData_ColorSelect(object sender , EventArgs e)
        {
            Label lbl = (Label)sender;
            ZoneData zd = (ZoneData)lbl.Parent;
            ColorDialog cd=new ColorDialog();
            cd.Color = zd.lbl_Color.BackColor;
            if (cd.ShowDialog() == DialogResult.OK)
            {
                zd.lbl_Color.BackColor = cd.Color;
                inifile.Write("BoxCurve" + zd.Tag.ToString() , "Color" , zd.lbl_Color.BackColor.ToArgb().ToString());
                ShowBoxCurve();
            }
        }
        private void ZoneData_CheckSelect(object sender , EventArgs e)
        {
            CheckBox cb = (CheckBox)sender;
            ZoneData zd = (ZoneData)cb.Parent;
            inifile.Write("BoxCurve" + zd.Tag.ToString() , "Selected" , zd.chk_ShowItem.Checked ? "1" : "0");
            ShowBoxCurve();
        }
        private void LoadBoxKeyTimeInterface()
        {
            lvKeyTime.Columns.Add("序号" , 40 , HorizontalAlignment.Center);
            lvKeyTime.Columns.Add("设备分区" , lvKeyTime.Width - 542 , HorizontalAlignment.Center);
            lvKeyTime.Columns.Add("进入时间" , 200 , HorizontalAlignment.Center);
            lvKeyTime.Columns.Add("移出时间" , 200 , HorizontalAlignment.Center);
            lvKeyTime.Columns.Add("停留时间" , 80 , HorizontalAlignment.Center);
            for (int i = 0 ; i < QueryForms.fmquery.netline.BoxKeyTime.Count ; i++)
            {
                lvKeyTime.Items.Add(new ListViewItem(new string[] { (i + 1).ToString() , QueryForms.fmquery.netline.BoxKeyTime[i].KeyTimeName , "-" , "-" , "-" }));
            }
        }
        private void LoadBoxInfoInterface()
        {
            grdProduct.Columns.Add("index" , "序号");
            grdProduct.Columns.Add("box" , "料框");
            grdProduct.Columns.Add("mark" , "标记");
            grdProduct.Columns.Add("weight" , "重量");
            grdProduct.Columns.Add("quenchmoveintime" , "淬火转移时间");
            grdProduct.Columns.Add("totalHeatTime" , "加热炉总时间");
            grdProduct.Columns.Add("loadtime", "加载时间");
            grdProduct.Columns.Add("batchserial", "批次编号");
            grdProduct.Columns.Add("createuser", "创建用户");
            grdProduct.Columns.Add("info0", "产品名称");
            grdProduct.Columns.Add("ProductVersion" , "ProductVersion");
            grdProduct.Columns["ProductVersion"].Visible = false;
            grdProduct.Columns["mark"].Visible = false;
            grdProduct.Columns["index"].Width = 60;
            grdProduct.Columns["box"].Width = 60;
            grdProduct.Columns["weight"].Width = 60;
            grdProduct.Columns["batchserial"].Width = 150;
            grdProduct.Columns["createuser"].Width = 150;
            grdProduct.Columns["loadtime"].Width = 150;
            grdProduct.Columns["info0"].Width = 150;
            grdProduct.Columns["quenchmoveintime"].Width = 111;
            grdProduct.Columns["totalHeatTime"].Width = 111;
            for (int i = 0 ; i < grdProduct.Columns.Count ; i++)
            {
                grdProduct.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
            }
        }


        private void ShowBoxCurve()
        {
            if (isEmptyBox) return;
            gp_LoadData.Visible = true;
            Application.DoEvents();
            pic_Curve.Image = null;
            pic_Curve.Controls.Clear();
            BoxData = GetBoxData(out StartTime , out EndTime);
            if (BoxData == null) { gp_LoadData.Visible = false; return; }
            //获取总时间，来确定pic_Curve的宽度，滚动条是否显示
            Xscale = 1;
            int totalminute=(int)EndTime.Subtract(StartTime).TotalMinutes;
            if (totalminute <= pic_Curve.Width)
            {
                if (totalminute != 0) Xscale = pic_Curve.Width / totalminute;
                totalminute = pic_Curve.Width;
            }
            hScroll.Visible = totalminute > pic_Curve.Width;
            Bitmap bm=new Bitmap(totalminute,pic_Curve.Height);

            DrawBgGrid(bm);
            if (BoxData.Length == 0)
            {
                pic_Curve.Image = bm;
                return;
            }
            DrawBoxLines(bm);
            pic_Curve.Image = bm;
            gp_LoadData.Visible = false;
        }

        private float[,] GetBoxData(out DateTime StartTime , out DateTime EndTime)
        {
            DateTime starttime=new DateTime(),endtime=new DateTime();
            DataTable dt;
            ZoneStartIntervalMinutes = new int[QueryForms.fmquery.netline.BoxKeyTime.Count];
            for (int i = 0 ; i < QueryForms.fmquery.netline.BoxKeyTime.Count ; i++)
            {
                //if (QueryForms.fmquery.netline.BoxKeyTime[i].keyZone.Count == 0) continue;
                if (QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime.Year > 2020 && QueryForms.fmquery.netline.BoxKeyTime[i].MoveOutTime.Year > 2020)
                {
                    if (starttime.Year < 2021) starttime = QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime;
                    endtime = QueryForms.fmquery.netline.BoxKeyTime[i].MoveOutTime;
                    ZoneStartIntervalMinutes[i] = (int)QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime.Subtract(starttime).TotalMinutes;
                }
            }
            
            int totalminutes=(int)endtime.Subtract(starttime).TotalMinutes;
            DateTime.TryParse(starttime.ToString("yyyy-MM-dd HH:mm:00"), out StartTime);
           // StartTime = starttime;
            DateTime.TryParse(endtime.ToString("yyyy-MM-dd HH:mm:00"), out EndTime);
           // EndTime = endtime;
            if (totalminutes <= 0) return null;
            dt = DBOperate.GetParameterData(starttime, endtime);
            dicZoneMaxMin.Clear();
            if (dt == null || dt.Rows.Count == 0) return null;
            float[,] recorderdata = new float[totalminutes, 4];

            for (int i = 0 ; i < QueryForms.fmquery.netline.BoxKeyTime.Count ; i++)
            {
                if (QueryForms.fmquery.netline.BoxKeyTime[i].keyZone.Count == 0 || ZoneStartIntervalMinutes[i] == 0) continue;
                //如果i+1越界，或者下一个分区的搬入时间节点无效，就只检索自己时间段内的数据
                StringBuilder sb = new StringBuilder("savetime>='");
                sb.Append(QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("' and savetime <='");
                if (i + 1 == QueryForms.fmquery.netline.BoxKeyTime.Count || QueryForms.fmquery.netline.BoxKeyTime[i + 1].MoveInTime.Year <= 2020)
                {
                    sb.Append(QueryForms.fmquery.netline.BoxKeyTime[i].MoveOutTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("'");
                }
                else
                {
                    sb.Append(QueryForms.fmquery.netline.BoxKeyTime[i + 1].MoveInTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("'");
                }
                DataRow[] rows=dt.Select(sb.ToString());
                int zonecount = 0;
                foreach (int zoneid in QueryForms.fmquery.netline.BoxKeyTime[i].keyZone.Keys)//遍历关联的zone
                {
                    int id = QueryForms.fmquery.netline.BoxKeyTime[i].KeyID * 1000 + zoneid;
                    dicZoneMaxMin.Add(id, new PVMaxMin()
                    {
                        zonename = QueryForms.fmquery.netline.BoxKeyTime[i].KeyTimeName,
                        mintime = QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime,
                        maxtime = QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime,
                        max = -100000f,
                        min = 100000f,
                    });
                    for (int j = 0; j < rows.Length; j++)
                    {
                        if (DateTime.TryParse(rows[j]["savetime"].ToString(), out endtime))//如果正确获取了每行数据的保存数据的时间值
                        {
                            DateTime.TryParse(endtime.ToString("yyyy-MM-dd HH:mm:00"), out endtime);
                            int minutediv = (int)endtime.Subtract(starttime).TotalMinutes;//计算从开始时间到获取时间的分钟的间隔数
                            if (minutediv >= 0 && minutediv < totalminutes)//如果在时间范围内
                            {
                                float.TryParse(rows[j][QueryForms.fmquery.netline.BoxKeyTime[i].keyZone[zoneid].pv.ID.ToString()].ToString(), out float val);
                                recorderdata[minutediv, zonecount * 2] = val;
                                if (dicZoneMaxMin[id].max < val)
                                {
                                    dicZoneMaxMin[id].max = val;
                                    dicZoneMaxMin[id].maxtime = endtime;
                                }
                                if (dicZoneMaxMin[id].min > val)
                                {
                                    dicZoneMaxMin[id].min = val;
                                    dicZoneMaxMin[id].mintime = endtime;
                                }
                                float.TryParse(rows[j][QueryForms.fmquery.netline.BoxKeyTime[i].keyZone[zoneid].sv.ID.ToString()].ToString(), out val);
                                recorderdata[minutediv, zonecount * 2 + 1] = val;
                            }
                        }
                    }
                    zonecount++;
                    if (zonecount > 1) break;//其实最多就两个zone，超过两个zone就退出foreach遍历
                }

            }
            return recorderdata;
        }
        private void DrawBgGrid(Bitmap bm)
        {
            if (bm.Width == 0 || bm.Height == 0) return;
            int h = bm.Height - YAxisHeight;
            int w=bm.Width;
            //画横向的线

            int smallDiv = h  / 50;
            int bigDiv = smallDiv*10;
            h = bigDiv * 5;
            CurveHeight = h;
            Graphics g = Graphics.FromImage(bm);
            Pen p = new Pen(Color.Gray, 1);

            for (int i = 0 ; i < 5 ; i++)
            {
                p.Color = Color.DarkGray;
                g.DrawLine(p , 0 , i * bigDiv , w , i * bigDiv);
                lbl_AxisRight[i].Top = lbl_AxisLeft[i].Top = i * bigDiv - 5;
                lbl_AxisRight[i].Text = Math.Round(limit[1 , 2] - limit[1 , 2] / 5 * i , 2).ToString();
                lbl_AxisLeft[i].Text = Math.Round(limit[1 , 0] - limit[1 , 0] / 5 * i , 2).ToString();
                p.Color = Color.LightGray;
                for (int j = 1 ; j < 10 ; j++)
                {
                    g.DrawLine(p , 0 , i * bigDiv + j * smallDiv , w , i * bigDiv + j * smallDiv);
                }
            }
            p.Color = Color.DarkGray;
            g.DrawLine(p , 0 , h , w , h);
            lbl_AxisRight[0].Top = lbl_AxisLeft[0].Top = 0;
            lbl_AxisRight[5].Top = lbl_AxisLeft[5].Top = h - 8;
            lbl_AxisRight[5].Text = lbl_AxisLeft[5].Text = "0";
            //画纵向的线
            SolidBrush brush = new SolidBrush(Color.Black);
            int xIndex = 0;
            int min=0;
            SizeF sf;
            StringBuilder sb;
            while (xIndex * 120 < w)
            {
                p.Color = Color.DarkGray;
                g.DrawLine(p , xIndex * 120 , 0 , xIndex * 120 , h);
                min = (xIndex * 120) / Xscale;
                //sb = new StringBuilder(xIndex.ToString("00") + ":00");
                sb = new StringBuilder().Append((min / 60).ToString("00")).Append(":").Append((min % 60).ToString("00"));
                sf = fdPublicFunction.GetTextSize(this.Font , sb);
                g.DrawString(sb.ToString() , this.Font , brush , new PointF(xIndex * 120f - sf.Width / 2 , h + 2));
                xIndex++;
            }
            g.DrawLine(p , w - 1 , 0 , w - 1 , h);
            g.DrawString(StartTime.ToString("yyyy-MM-dd HH:mm:00") , this.Font , brush , new PointF(0 , h + 14));
            string s=StartTime.AddMinutes(bm.Width/Xscale).ToString("yyyy-MM-dd HH:mm:00");
            g.DrawString(s , this.Font , brush , new PointF(bm.Width - g.MeasureString(s , this.Font).Width + 2 , h + 14));

            if (!z[4].chk_ShowItem.Checked) return;
            //绘制分区分隔线，并添加文字lbl

            p.Color = z[4].lbl_Color.BackColor;

            if (QueryForms.fmquery.netline.BoxKeyTime[0].MoveInTime.Year >= 2021)
            {
                Label lbl=new Label()
                {
                    BorderStyle=BorderStyle.FixedSingle,
                    Text=QueryForms.fmquery.netline.BoxKeyTime[0].KeyTimeName,
                    Location=new Point(1,0),
                    AutoSize=true,
                };
                pic_Curve.Controls.Add(lbl);
            }

            for (int i = 1 ; i < ZoneStartIntervalMinutes.Length ; i++)
            {
                if (ZoneStartIntervalMinutes[i] > 0)
                {
                    g.DrawLine(p , ZoneStartIntervalMinutes[i] * Xscale , 0 , ZoneStartIntervalMinutes[i] * Xscale , h);
                    Label lbl=new Label()
                    {
                        BorderStyle=BorderStyle.FixedSingle,
                        Text=QueryForms.fmquery.netline.BoxKeyTime[i].KeyTimeName,
                        Location=new Point(ZoneStartIntervalMinutes[i] * Xscale +1,i%3 * 15),
                        AutoSize=true,
                    };
                    Equiplbl.Add(lbl);
                    pic_Curve.Controls.Add(lbl);
                }
            }
        }
        private void DrawBoxLines(Bitmap bm)
        {
            int length=BoxData.Length/4;
            Graphics gp = Graphics.FromImage(bm);
            for (int i = 3 ; i >= 0 ; i--)
            {
                if (!z[i].chk_ShowItem.Checked) continue;
                Pen p=new Pen(z[i].lbl_Color.BackColor,2);
                float x0, y0, x1, y1;
                x0 = 0;
                y0 = CurveHeight * (limit[1 , i] - BoxData[0 , i]) / limit[1 , i];
                for (int j = 1 ; j < length ; j++)
                {
                   // if (BoxData[j, i] == 0) BoxData[j, i] = BoxData[j - 1, i];//如果数据出现为0的情况，参照使用前面的数据
                    y1 = CurveHeight * (limit[1 , i] - BoxData[j , i]) / limit[1 , i];
                    x1 = j * Xscale;
                    if (BoxData[j , i] * BoxData[j - 1 , i] != 0)
                    {
                        gp.DrawLine(p , x0 , y0 , x1 , y1);
                    }
                    y0 = y1;
                    x0 = x1;
                }
            }
        }

        private void ShowBox()
        {
            if (isLoadInterface) return;
            showProcessBoxbyDay(dtp_Day.Value);
            Application.DoEvents();
            if (grdProduct.Rows.Count > 0)
            {
                lbl_ListTitle.Text = dtp_Day.Value.ToString("yyyy年MM月dd日 生产信息");
                grdProduct.Rows[0].Selected = true;
                SetBoxKeyTime();
                Application.DoEvents();
                ShowBoxCurve();
            }
            else
            {
                lbl_ListTitle.Text = dtp_Day.Value.ToString("yyyy年MM月dd日 无生产信息");
            }
        }

        private void showProcessBoxbyDay(DateTime SearchDay)
        {
            grdProduct.Rows.Clear();
            BoxDetail = DBOperate.GetProcessBoxByTime(SearchDay.Date , SearchDay.AddDays(1).Date.AddSeconds(-1));
            if (BoxDetail == null || BoxDetail.Rows.Count == 0) return;
            grdProduct.Rows.Add(BoxDetail.Rows.Count);
            for (int i = 0 ; i < BoxDetail.Rows.Count ; i++)
            {
                grdProduct.Rows[i].Cells[0].Value = i + 1;
                for (int j = 1 ; j < grdProduct.Columns.Count ; j++)
                {
                    if(BoxDetail.Columns.Contains(grdProduct.Columns[j].Name))
                        grdProduct.Rows[i].Cells[j].Value = BoxDetail.Rows[i][grdProduct.Columns[j].Name];
                    grdProduct.Rows[i].Cells["totalHeatTime"].Value = GetPassingTimeOfHeatingFurnace(BoxDetail.Rows[i]["keytime"+ QueryForms.fmquery.netline.KeytimeIndex[0]], BoxDetail.Rows[i]["keytime" + QueryForms.fmquery.netline.KeytimeIndex[1]]);
                }
            }
        }

        private string GetPassingTimeOfHeatingFurnace(object inTime,object outTime)
        {
            if(DateTime.TryParse(inTime.ToString(),out DateTime intime) && DateTime.TryParse(outTime.ToString(), out DateTime outime))
            {
                TimeSpan ts = outime.Subtract(intime);
                return (new StringBuilder(ts.Hours.ToString()).Append(":").Append(ts.Minutes).Append(":").Append(ts.Seconds)).ToString();
            }
            return string.Empty;
        }

        private void SetBoxKeyTime()
        {
            KeyTimeForAlarm.Clear();
            if (grdProduct.SelectedRows != null)
            {
                isEmptyBox = false;
                lbl_BoxInfoTitle.Text = grdProduct.SelectedRows[0].Cells["box"].Value.ToString() + " 号料框信息";
                DateTime dt1,dt2;
                for (int i = 0 ; i < QueryForms.fmquery.netline.BoxKeyTime.Count ; i++)
                {
                    DateTime.TryParse(BoxDetail.Rows[grdProduct.SelectedRows[0].Index]["keytime" + QueryForms.fmquery.netline.BoxKeyTime[i].KeyTimeInIndex].ToString() , out dt1);
                    DateTime.TryParse(BoxDetail.Rows[grdProduct.SelectedRows[0].Index]["keytime" + QueryForms.fmquery.netline.BoxKeyTime[i].KeyTimeOutIndex].ToString() , out dt2);
                    QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime = dt1;
                    QueryForms.fmquery.netline.BoxKeyTime[i].MoveOutTime = dt2;
                    bool isok1 = !( dt1.Year < 2021);
                    lvKeyTime.Items[i].SubItems[2].Text = isok1 ? dt1.ToString("yyyy-MM-dd HH:mm:ss") : "-";
                    bool isok2 =!(dt2.Year < 2021);
                    lvKeyTime.Items[i].SubItems[3].Text = isok2 ? dt2.ToString("yyyy-MM-dd HH:mm:ss") : "-";
                    if (isok1 && isok2)
                    {
                        KeyTimeForAlarm.Add(QueryForms.fmquery.netline.BoxKeyTime[i]);
                        TimeSpan ts= dt2.Subtract(dt1);
                        lvKeyTime.Items[i].SubItems[4].Text = (new StringBuilder(ts.Hours.ToString()).Append(":").Append(ts.Minutes).Append(":").Append(ts.Seconds)).ToString();
                    }
                    else
                        lvKeyTime.Items[i].SubItems[4].Text = "-";
                    Application.DoEvents();
                }
            }
            else
            {
                isEmptyBox = true;
                lbl_BoxInfoTitle.Text = "-";
                for (int i = 0 ; i < QueryForms.fmquery.netline.BoxKeyTime.Count ; i++)
                {
                    lvKeyTime.Items[i].SubItems[2].Text = lvKeyTime.Items[i].SubItems[3].Text = "-";
                }
            }
            
        }

        private void grdProduct_CellClick(object sender , DataGridViewCellEventArgs e)
        {
            SetBoxKeyTime();
            ShowBoxCurve();
        }

        private void btn_ShowBoxMaxMin_Click(object sender , EventArgs e)
        {
            if (BoxData!=null && BoxData.Length > 0)
            {
                dicZoneMaxMin.Clear();
                for (int i = 0 ; i < QueryForms.fmquery.netline.BoxKeyTime.Count ; i++)
                {
                    if (QueryForms.fmquery.netline.BoxKeyTime[i].keyZone.Count > 0)
                    {
                        int startindex=(int)QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime.Subtract(StartTime).TotalMinutes;
                        int endindex=(int)QueryForms.fmquery.netline.BoxKeyTime[i].MoveOutTime.Subtract(StartTime).TotalMinutes;
                        if (startindex < 0 || endindex<0 || endindex>BoxData.Length/4 || startindex > BoxData.Length/4) continue;
                        int zonecount=0;
                        foreach (int item in QueryForms.fmquery.netline.BoxKeyTime[i].keyZone.Keys)
                        {
                            if (zonecount > 1) break;
                            int keyid= QueryForms.fmquery.netline.BoxKeyTime[i].KeyID*1000+item;
                            dicZoneMaxMin.Add(keyid, new PVMaxMin() {
                                zonename = QueryForms.fmquery.netline.BoxKeyTime[i].keyZone[item].ZoneName,
                                mintime = QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime,
                                maxtime = QueryForms.fmquery.netline.BoxKeyTime[i].MoveInTime,
                                max= BoxData[startindex , zonecount * 2],
                                min= BoxData[startindex , zonecount * 2] ,
                            });
                            for (int k = startindex ; k < endindex ; k++)
                            {
                                if (dicZoneMaxMin[keyid].min > BoxData[k , zonecount * 2])
                                {
                                    dicZoneMaxMin[keyid].min = BoxData[k , zonecount * 2];
                                    dicZoneMaxMin[keyid].mintime = StartTime.AddMinutes(k);
                                }
                                if (dicZoneMaxMin[keyid].max < BoxData[k , zonecount * 2])
                                {
                                    dicZoneMaxMin[keyid].max = BoxData[k , zonecount * 2];
                                    dicZoneMaxMin[keyid].maxtime = StartTime.AddMinutes(k);
                                }
                            }
                            zonecount++;
                        }
                    }
                }
                if (dicZoneMaxMin.Count > 0)
                {
                    Form_DayMaxMin fmmaxmin=new Form_DayMaxMin(dicZoneMaxMin);
                    fmmaxmin.ShowDialog();
                }
            }
            else
            {
                MessageBox.Show("无该料框的相关数据信息。");
            }
        }

        private void btn_ShowBoxAlarm_Click(object sender , EventArgs e)
        {
            if (KeyTimeForAlarm.Count == 0)
            {
                MessageBox.Show("该料框还没有进行到关键设备进行处理。请稍后查询！");
                return;
            }
            Form_QueryAlarmByBox fmboxalarm=new Form_QueryAlarmByBox(StartTime,EndTime,KeyTimeForAlarm);
            fmboxalarm.ShowDialog();
        }

        private void dtp_Day_ValueChanged(object sender, EventArgs e)
        {
            ShowBox();
        }

        #region box报告 printer
        private PrintDocument print = new PrintDocument();//关联printpage事件在界面的load过程中
        private string DefaultPrinterName = "";
        DataRow[] PrintDataRow = null;
        SizeF pageSize;
        float pageMargin = 30f;
        float MarginScale = 0.0336134f;
        int CurrentPage = 0;
        int TotalPages = 4;

        float TitleHeight = 0;
        float LabelHeight = 0;

        string LoadDate ="";

        List<Graphics> gph = new List<Graphics>();

        DataTable hisDatatable= null;

        private void btn_PrintReport_Click(object sender, EventArgs e)
        {
            DefaultPrinterName = PubPrint.LoadPrinters(print, cmb_Printers);
            pnl_Print.Visible = true;
        }
        private void Print_PrintPage(object sender, PrintPageEventArgs e)
        {
            switch (CurrentPage)
            {
                case 0://打印基本信息，工艺                    
                    printPageBoxinfo(e.Graphics, PrintDataRow[0]);
                    break;
                case 1://打印时间信息
                    PrintPageKeyTime(e.Graphics, PrintDataRow[0]);
                    break;
                case 2://打印警报信息，目前最多打印30个
                    PrintAlarmInfo(e.Graphics, PrintDataRow[0]);
                    break;
                case 3://打印整体曲线
                    e.Graphics.TranslateTransform(pageSize.Width, 0);
                    e.Graphics.RotateTransform(90);
                    PrintCurvePage(e.Graphics, PrintDataRow[0]);
                    break;
                default:
                    break;
            }
            CurrentPage++;
            e.HasMorePages = CurrentPage < TotalPages;
        }
        private void btn_PrintConfirm_Click(object sender, EventArgs e)
        {
            if (grdProduct.SelectedRows == null) return;
            if (DateTime.TryParse(grdProduct.SelectedRows[0].Cells["loadtime"].Value.ToString(), out DateTime x))
                LoadDate = x.ToString("yyyy-MM-dd");
            CurrentPage = 0;
            string _printBox = grdProduct.SelectedRows[0].Cells["box"].Value.ToString();
            string _printMark = grdProduct.SelectedRows[0].Cells["mark"].Value.ToString();
            PrintDataRow = BoxDetail.Select(string.Format("box='{0}' and mark='{1}'", _printBox, _printMark));//在datatable中查找对应的行，用来后面的数据输出
            if (PrintDataRow.Length <= 0) return;
            if (DefaultPrinterName == "") return;
            if (DefaultPrinterName != cmb_Printers.Text) //保存为默认打印机
            {
                DefaultPrinterName = cmb_Printers.Text;
                PubPrint.SaveDefaultPrinter(DefaultPrinterName);
            }
            print.PrinterSettings.PrinterName = DefaultPrinterName;
            pageSize = new SizeF(print.PrinterSettings.DefaultPageSettings.PrintableArea.Width, print.PrinterSettings.DefaultPageSettings.PrintableArea.Height);
            pageMargin = print.PrinterSettings.DefaultPageSettings.PrintableArea.Width * MarginScale;
            print.Print();
            pnl_Print.Visible = false;
        }

        private void printPageBoxinfo(Graphics g, DataRow row)
        {
            //绘制页面
            TitleHeight= PrintTitle(g, QueryForms.fmquery.netline.LineName + " - " + LoadDate + " Box " + row["box"].ToString().PadLeft(4, '0'));
            //打印零件基本信息

            if (ProductInfoTitle == null || ProductInfoTitle.Rows.Count == 0) return;
            float nexttop = PrintGroup(g, "生产信息", new RectangleF(pageMargin, pageMargin+TitleHeight*1.2f, pageSize.Width - pageMargin * 2, 1));
            float gap = pageSize.Width * 0.01f;
            float w = (pageSize.Width - pageMargin * 2 - 3 * gap) / 4;
            PrintContent(g, new RectangleF(pageMargin, nexttop, w, 20), grdProduct.Columns["batchserial"].HeaderText, true);//打印的信息名称
            PrintContent(g, new RectangleF(pageMargin + (w + gap), nexttop, w, 20), grdProduct.SelectedRows[0].Cells["batchserial"].Value.ToString(), false);//打印内容
            PrintContent(g, new RectangleF(pageMargin + (w + gap) * 2, nexttop, w, 20), grdProduct.Columns["createuser"].HeaderText, true);//打印的信息名称
            nexttop = PrintContent(g, new RectangleF(pageMargin + (w + gap) * 3, nexttop, w, 20), grdProduct.SelectedRows[0].Cells["createuser"].Value.ToString(), false);//打印内容
            PrintContent(g, new RectangleF(pageMargin, nexttop, w, 20), grdProduct.Columns["info0"].HeaderText, true);//打印的信息名称
            PrintContent(g, new RectangleF(pageMargin + (w + gap), nexttop, w, 20), grdProduct.SelectedRows[0].Cells["info0"].Value.ToString(), false);//打印内容
            PrintContent(g, new RectangleF(pageMargin + (w + gap) * 2, nexttop, w, 20), grdProduct.Columns["loadtime"].HeaderText, true);//打印的信息名称
            nexttop = PrintContent(g, new RectangleF(pageMargin + (w + gap) * 3, nexttop, w, 20), grdProduct.SelectedRows[0].Cells["loadtime"].Value.ToString(), false);//打印内容
            PrintContent(g, new RectangleF(pageMargin, nexttop, w, 20), grdProduct.Columns["quenchmoveintime"].HeaderText, true);//打印的信息名称
            PrintContent(g, new RectangleF(pageMargin + (w + gap), nexttop, w, 20), grdProduct.SelectedRows[0].Cells["quenchmoveintime"].Value.ToString(), false);//打印内容
            PrintContent(g, new RectangleF(pageMargin + (w + gap) * 2, nexttop, w, 20), grdProduct.Columns["totalHeatTime"].HeaderText, true);//打印的信息名称
            nexttop = PrintContent(g, new RectangleF(pageMargin + (w + gap) * 3, nexttop, w, 20), grdProduct.SelectedRows[0].Cells["totalHeatTime"].Value.ToString(), false);//打印内容
            nexttop = PrintGroup(g, "工艺信息", new RectangleF(pageMargin, nexttop, pageSize.Width - pageMargin * 2, 1));
            //获取工艺内容，并进行相关的打印，从历史数据中获取相关的数据。

            hisDatatable = DBOperate.GetParameterData(StartTime, EndTime);
            for (int i = 0; i<lstzone.Count; i++)
            {
                if (i % 2 == 0)
                {
                    PrintProContent(g, new RectangleF(pageMargin, nexttop, w * 1.5f, 20), lstzone[i].ZoneName, 10f, Color.DarkSlateGray, Color.WhiteSmoke, true);//打印内容
                    PrintProContent(g, new RectangleF(pageMargin + w * 1.5f + gap, nexttop, w * 0.5f, 20), hisDatatable.Rows[0][lstzone[i].sv.ID.ToString()].ToString(), 10f, Color.DarkSlateGray, Color.WhiteSmoke, false);//打印内容
                }
                else
                {
                    PrintProContent(g, new RectangleF(pageMargin + (w + gap) * 2, nexttop, w * 1.5f, 20), lstzone[i].ZoneName, 10f, Color.DarkSlateGray, Color.WhiteSmoke, true);//打印内容
                    nexttop = PrintProContent(g, new RectangleF(pageMargin + (w + gap) * 3 + w * 0.5f, nexttop, w * 0.5f, 20), hisDatatable.Rows[0][lstzone[i].sv.ID.ToString()].ToString(), 10f, Color.DarkSlateGray, Color.WhiteSmoke, false);//打印内容
                }
            }

        }
        private void PrintPageKeyTime(Graphics g,DataRow row)
        {
            //string[] _headTitle = new string[5] { "Index", "Equip Zone", "Move in time", "Move out time", "Stay" };
            string[] _headTitle = new string[5] { "序号", "设备分区", "进入时间", "移出时间", "停留时间" };
            float[] _headWidth = new float[5] { 10, 23, 25, 25, 17f };
            //绘制页面
            TitleHeight = PrintTitle(g, QueryForms.fmquery.netline.LineName + " - " + LoadDate + " Box " + row["box"].ToString().PadLeft(4, '0'));
            PrintLog(g);
            float nexttop= PrintGroup(g, "料框转移时间节点", new RectangleF(pageMargin, pageMargin+ TitleHeight, pageSize.Width- pageMargin * 2, 762));
            float gap= (pageSize.Width - 2 * pageMargin) * 0.01f;
            float w = (pageSize.Width-2*pageMargin)/100f;
            float nextleft = pageMargin;
            for (int i = 0; i < 4; i++)
            {
                PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[i]*w-gap, 20), _headTitle[i], true);
                nextleft += _headWidth[i] * w;
            }
            nexttop=PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[4] * w, 20), _headTitle[4], true);

            for (int i = 0; i < lvKeyTime.Items.Count; i++)
            {
                nextleft = pageMargin;
                for (int j = 0; j < 4; j++)
                {
                    PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[j] * w - gap, 20), lvKeyTime.Items[i].SubItems[j].Text, false);
                    nextleft += _headWidth[j] * w;
                }
                nexttop=  PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[4] * w, 20), lvKeyTime.Items[i].SubItems[4].Text, false);
            }
        }
        private void PrintAlarmInfo(Graphics g, DataRow row)
        {
            List<string[]> lst_Alarm = GetBoxAlarmList();
            
            string[] _headTitle = new string[5] { "序号", "警报名称", "警报等级", "发生时间", "复位时间" };
            float[] _headWidth = new float[5] { 7, 37, 10, 23, 23 };
            TitleHeight = PrintTitle(g, QueryForms.fmquery.netline.LineName + " - " + LoadDate + " Box " + row["box"].ToString().PadLeft(4, '0'));
            PrintLog(g);
            float nexttop = PrintGroup(g, "料框警报信息", new RectangleF(pageMargin, pageMargin + TitleHeight, pageSize.Width - pageMargin * 2, 762));
            float gap = (pageSize.Width - 2 * pageMargin) * 0.01f;
            float w = (pageSize.Width - 2 * pageMargin) / 100f;
            float nextleft = pageMargin;
            for (int i = 0; i < 4; i++)
            {
                PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[i] * w - gap, 20), _headTitle[i], true);
                nextleft += _headWidth[i] * w;
            }
            nexttop = PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[4] * w, 20), _headTitle[4], true);

            if (lst_Alarm == null)
            {
                PrintContent(g, new RectangleF(pageMargin, nexttop, pageSize.Width -pageMargin*2, 20), "当前物料生产过程中未发生异常", false);
                return;
            }

            for (int i = 0; i < lst_Alarm.Count && i<31; i++)
            {
                nextleft = pageMargin;
                for (int j = 0; j < 4; j++)
                {
                    PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[j] * w - gap, 20), lst_Alarm[i][j], false);
                    nextleft += _headWidth[j] * w;
                }
                nexttop = PrintContent(g, new RectangleF(nextleft, nexttop, _headWidth[4] * w, 20), lst_Alarm[i][4], false);
            }
        }
        private void PrintCurvePage(Graphics g, DataRow row)
        {
            TitleHeight = PrintTitle(g, QueryForms.fmquery.netline.LineName + " - " + LoadDate + " Box " + row["box"].ToString().PadLeft(4,'0'));
            LabelHeight = GetLabelHeight(g);
            PointF CurveLoaction = new PointF(pageMargin, pageMargin + TitleHeight+ LabelHeight);
            SizeF CurveSizeF = new SizeF(pageSize.Height - pageMargin * 2, 0.8f * (pageSize.Width - TitleHeight- LabelHeight - 2 * pageMargin));
            PrintLabels(g,new PointF(pageMargin, pageMargin + TitleHeight),new SizeF(pageSize.Height - pageMargin * 2, LabelHeight));
            PrintAxis(g, CurveLoaction, CurveSizeF, StartTime, EndTime);
            PrintCurve(g, CurveLoaction, CurveSizeF);
            PrintTips(g, new PointF(pageMargin, TitleHeight + LabelHeight + 0.95f * (pageSize.Width - TitleHeight - LabelHeight - 2 * pageMargin)));
        }
        private void PrintCurve(Graphics g, PointF CurveLoaction, SizeF CurveSizeF)
        {
            int length = BoxData.Length / 4;
            Font fontAxis = new Font("微软雅黑", 8f, FontStyle.Regular);
            SizeF sf = g.MeasureString("9.999", fontAxis);
            float Axisleft = CurveLoaction.X + sf.Width * 1.02f;
            float Axisright = CurveLoaction.X + CurveSizeF.Width - sf.Width * 1.02f;
            float div = (Axisright - Axisleft) / length;
            for (int i = 3; i >= 0; i--)
            {
                if (!z[i].chk_ShowItem.Checked) continue;
                Pen p = new Pen(z[i].lbl_Color.BackColor, 2);
                float x0, y0, x1, y1;
                x0 = Axisleft;
                y0 = CurveLoaction.Y+ CurveSizeF.Height  * (limit[1, i] - BoxData[0, i]) / limit[1, i];
                for (int j = 1; j < length; j++)
                {
                    y1 = CurveLoaction.Y + CurveSizeF.Height * (limit[1, i] - BoxData[j, i]) / limit[1, i];
                    x1 = Axisleft+j * div;
                    if (BoxData[j, i] * BoxData[j - 1, i] != 0)
                    {
                        g.DrawLine(p, x0, y0, x1, y1);
                    }
                    y0 = y1;
                    x0 = x1;
                }
            }

        }
        private void PrintAxis(Graphics g, PointF CurveLoaction, SizeF CurveSizeF, DateTime _startTime, DateTime _endTime)
        {
            int TimeInterval = 5;
            Pen linePen = new Pen(Color.DarkGray);
            Pen linePen2 = new Pen(Color.LightGray);
            Brush brush = new SolidBrush(Color.Black);
            Font fontAxis = new Font("微软雅黑", 8f, FontStyle.Regular);
            SizeF sf = g.MeasureString("9.999", fontAxis);
            float Axisleft = CurveLoaction.X + sf.Width * 1.02f;
            float Axisright = CurveLoaction.X+ CurveSizeF.Width - sf.Width * 1.02f;
            float Axistop = CurveLoaction.Y;
            float AxisHeight = CurveSizeF.Height;
            float AxisDivHeight = AxisHeight / 5f;
            //画横向的线
            string[] LAxis = new string[6];
            string[] RAxis = new string[6];
            for (int i = 1; i < 5; i++)
            {
                LAxis[i] = ( (5 - i) * (limit[1, 0] - limit[0, 0]) / 5).ToString();
                RAxis[i] = ( (5 - i) * (limit[1, 2] - limit[0, 2]) / 5).ToString();
            }
            LAxis[5] = limit[0, 0].ToString();
            LAxis[0] = limit[1, 0].ToString();
            RAxis[5] = limit[0, 2].ToString();
            RAxis[0] = limit[1, 2].ToString();
            SizeF v;
            for (int i = 0; i < 5; i++)
            {
                g.DrawLine(linePen, new PointF(Axisleft, Axistop + AxisDivHeight * i), new PointF(Axisright, Axistop + AxisDivHeight * i));
                v = g.MeasureString(LAxis[i], fontAxis);
                if (limit[0, 0] != limit[1, 0]) g.DrawString(LAxis[i], fontAxis, brush, new PointF(Axisleft - sf.Width * 0.02f - v.Width, Axistop + AxisDivHeight * i - v.Height / 2));
                if (limit[0, 2] != limit[1, 2]) g.DrawString(RAxis[i], fontAxis, brush, new PointF(Axisright + 0.02f * sf.Width, Axistop + AxisDivHeight * i - v.Height / 2));
                for (int j = 1; j < 10; j++)
                {
                    g.DrawLine(linePen2, new PointF(Axisleft, Axistop + AxisDivHeight * i + j * (AxisDivHeight / 10)), new PointF(Axisright, Axistop + AxisDivHeight * i + j * (AxisDivHeight / 10)));
                }
            }
            g.DrawLine(linePen, new PointF(Axisleft, Axistop + AxisDivHeight * 5), new PointF(Axisright, Axistop + AxisDivHeight * 5));
            v = g.MeasureString(LAxis[5], fontAxis);
            if (limit[0, 0] != limit[1, 0]) g.DrawString(LAxis[5], fontAxis, brush, new PointF(Axisleft - sf.Width * 0.02f - v.Width, Axistop + AxisDivHeight * 5 - v.Height / 2));
            if (limit[0, 2] != limit[1, 2]) g.DrawString(RAxis[5], fontAxis, brush, new PointF(Axisright + 0.02f * sf.Width, Axistop + AxisDivHeight * 5 - v.Height / 2));
            //画纵向的线
            //基本计算
            DateTime a = Convert.ToDateTime(_startTime.AddHours(1).ToString("yyyy-MM-dd HH" + ":00"));
            DateTime b = Convert.ToDateTime(_endTime.ToString("yyyy-MM-dd HH" + ":00"));
            TimeInterval = (int)b.Subtract(a).TotalMinutes / 12;
            for (int i = 0; i < TimeSep.Length; i++)
            {
                if (TimeInterval <= TimeSep[i])
                {
                    TimeInterval = TimeSep[i];
                    break;
                }
            }
            float totalMinutes = (float)_endTime.Subtract(_startTime).TotalMinutes;
            int HourLines = (int)totalMinutes / TimeInterval;
            float w =( Axisright - Axisleft) * (TimeInterval / totalMinutes);
            float FirstLeft = Axisleft;
            DateTime FirstTime=_startTime;
            if (_startTime.Minute != 0)
            {
                FirstLeft += (Axisright - Axisleft) / (totalMinutes) * (60 - _startTime.Minute);
                FirstTime = _startTime.AddMinutes(60 - _startTime.Minute);
            }
            //开始画线
            g.DrawLine(linePen, new PointF(Axisleft, Axistop), new PointF(Axisleft, Axistop + AxisDivHeight * 5));
            g.DrawLine(linePen, new PointF(Axisright, Axistop), new PointF(Axisright, Axistop + AxisDivHeight * 5));
            string TimeString = "";
            for (int i = (FirstLeft == Axisleft? 1:0); i < HourLines && FirstLeft + w * i < Axisright; i++)
            {
                TimeString = FirstTime.AddMinutes(TimeInterval * i).ToString("HH:mm");
                v = g.MeasureString(TimeString, fontAxis);
                g.DrawLine(linePen, new PointF(FirstLeft + w * i, Axistop), new PointF(FirstLeft + w * i, Axistop + AxisDivHeight * 5.01f));
                g.DrawString(TimeString, fontAxis, brush, new PointF(FirstLeft + w * i - v.Width / 2, Axistop + AxisDivHeight * 5.02f));
            }
            string s = _startTime.ToString("yyyy-MM-dd HH:mm");
            g.DrawString(s, fontAxis, brush, new PointF(Axisleft, Axistop + AxisDivHeight * 5.05f + sf.Height));
            s = _endTime.ToString("yyyy-MM-dd HH:mm");
            v = g.MeasureString(s, fontAxis);
            g.DrawString(s, fontAxis, brush, new PointF(Axisright - v.Width + 0.5f * sf.Width, Axistop + AxisDivHeight * 5.05f + sf.Height));
            s = TimeInterval + "Minutes/div";
            v = g.MeasureString(s, fontAxis);
            g.DrawString(s, fontAxis, brush, new PointF((Axisleft+ Axisright) / 2 - sf.Width / 2f, Axistop + AxisDivHeight * 5.05f + sf.Height));
        }
        private float GetLabelHeight(Graphics g)
        {
            if (!z[4].chk_ShowItem.Checked) { return 0f; }
            Font fontAxis = new Font("微软雅黑", 8f, FontStyle.Regular);
            SizeF sf = g.MeasureString("Test中文", fontAxis);
            return sf.Height * 4.8f;
        }
        private void PrintLabels(Graphics g,PointF LabelLocation,SizeF LabelSizeF)
        {
            if (!z[4].chk_ShowItem.Checked) return;
            Font fontAxis = new Font("微软雅黑", 8f, FontStyle.Regular);
            SizeF sf = g.MeasureString("9.999", fontAxis);
            float Axisleft = LabelLocation.X + sf.Width * 1.02f;
            float Axisright = LabelLocation.X + LabelSizeF.Width - sf.Width * 1.02f;
            Pen p =new Pen(z[4].lbl_Color.BackColor);
            float w= (Axisright - Axisleft )/ (BoxData.Length / 4f);

            for (int i = 0; i < lvKeyTime.Items.Count; i++)
            {
                if(DateTime.TryParse(lvKeyTime.Items[i].SubItems[2].Text,out DateTime v1) && DateTime.TryParse(lvKeyTime.Items[i].SubItems[3].Text, out DateTime v2))
                {
                    float t =(float) v1.Subtract(StartTime).TotalMinutes * w;
                    if (t > 0)
                    {
                        g.DrawLine(p, Axisleft + t, LabelLocation.Y, Axisleft + t, LabelLocation.Y + LabelSizeF.Height);
                        g.DrawString(lvKeyTime.Items[i].SubItems[1].Text,
                        fontAxis,
                        new SolidBrush(Color.Black),
                        new PointF(Axisleft + t, LabelLocation.Y + i % 4 * (sf.Height * 1.2f)));
                    }
                }
            }
        }
        private float PrintTitle(Graphics g, string title, int lcr=0)
        {
            Font ft = new Font("微软雅黑", 16f, FontStyle.Regular);
            Brush brush = new SolidBrush(Color.Black);//画刷  
            SizeF sf = g.MeasureString(title, ft); //  g.GetTextSize(ft, title).Width;
            float left = pageMargin;
            if (lcr == 1) left = (pageSize.Width - sf.Width ) / 2;
            if (lcr == 2) left = pageSize.Width - sf.Width ;
            g.DrawString(title, ft, brush, new PointF(left, pageMargin));
            return sf.Height;
        }
        private void PrintTips(Graphics g,PointF TipLocation)
        {
            int zIndex = 0;
            float w = (pageSize.Height - 2 * pageMargin)/4f;
            Font ft = new Font("微软雅黑", 12f, FontStyle.Regular);
            SizeF sf = g.MeasureString("中文", ft);
            for (int i = 0; i <4; i++)
            {
                if (z[i].chk_ShowItem.Checked)
                {
                    g.FillRectangle(new SolidBrush(z[i].lbl_Color.BackColor), new RectangleF(TipLocation.X+w*zIndex, TipLocation.Y+sf.Height * 0.1f, sf.Height * 0.8f, sf.Height * 0.8f));
                    g.DrawString(z[i].lbl_Name.Text, ft, new SolidBrush(Color.Black), TipLocation.X + w * zIndex + sf.Height, TipLocation.Y);
                    zIndex++;
                }
            }
        }

        private List<string[]> GetBoxAlarmList()
        {
            DataTable dt = DBOperate.his_GetAlarmValues(StartTime, EndTime);
            if (dt == null) return null;
            List<DataRow> dr = new List<DataRow>();
            DataRow[] preDatarow;
            DataRow[] currentDatarow;
            DataRow[] nextDatarow;
            StringBuilder sbSelect = new StringBuilder();
            if (dt != null)
            {
                for (int i = 0; i < KeyTimeForAlarm.Count; i++)
                {
                    for (int j = 0; j < KeyTimeForAlarm[i].Alarmid.Count; j++)
                    {
                        sbSelect.Clear().Append("savetime <'").Append(KeyTimeForAlarm[i].MoveInTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("'")
                            .Append(" and alarmid='").Append(KeyTimeForAlarm[i].Alarmid[j]).Append("'");// and AlarmActive='1'");
                        preDatarow = dt.Select(sbSelect.ToString(), "savetime desc");
                        sbSelect.Clear().Append("savetime >='").Append(KeyTimeForAlarm[i].MoveInTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("'")
                            .Append(" and savetime<='").Append(KeyTimeForAlarm[i].MoveOutTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("'")
                            .Append(" and alarmid='").Append(KeyTimeForAlarm[i].Alarmid[j]).Append("'");
                        currentDatarow = dt.Select(sbSelect.ToString());
                        sbSelect.Clear().Append("savetime >'").Append(KeyTimeForAlarm[i].MoveOutTime.ToString("yyyy-MM-dd HH:mm:ss")).Append("'")
                            .Append(" and alarmid='").Append(KeyTimeForAlarm[i].Alarmid[j]).Append("'");// and AlarmActive='0'");
                        nextDatarow = dt.Select(sbSelect.ToString());
                        if (preDatarow.Length > 0 && preDatarow[0]["AlarmActive"].ToString() == "1") dr.Add(preDatarow[0]);
                        dr.AddRange(currentDatarow);
                        if (nextDatarow.Length > 0 && nextDatarow[0]["AlarmActive"].ToString() == "0") dr.Add(nextDatarow[0]);
                    }
                }
            }
            else
            {
                return null;
            }

            List<string[]> lst_Alarm = new List<string[]>();
            if (dr.Count > 0)
            {
                dt = dr.ToArray().CopyToDataTable().DefaultView.ToTable(true);
                dr.Clear();
                dr.AddRange(dt.Select());
                //显示报警内容
                for (int i = dr.Count - 1; i >= 0; i--)
                {
                    if (dr[i]["AlarmActive"].ToString() == "0")
                    {
                        lst_Alarm.Add(new string[] { (lst_Alarm.Count + 1).ToString(), dr[i]["AlarmName"].ToString(), dr[i]["AlarmLevel"].ToString(), "", dr[i]["SaveTime"].ToString() });//最后是报警等级，最后修改
                    }
                    else
                    {
                        //1这里加载数据，对数据进行重组
                        int lastindex = -10;
                        for (int k = lst_Alarm.Count - 1; k >= 0; k--)
                        {
                            if (dr[i]["AlarmName"].ToString() == lst_Alarm[k][1] && lst_Alarm[k][3] == "")
                            {
                                lst_Alarm[k][3] = dr[i]["SaveTime"].ToString();
                                lastindex = k;
                                break;
                            }
                        }
                        if (lastindex == -10)
                        {
                            lst_Alarm.Add(new string[] { (lst_Alarm.Count + 1).ToString(), dr[i]["AlarmName"].ToString(), dr[i]["AlarmLevel"].ToString(), dr[i]["SaveTime"].ToString(), "" });
                        }
                    }
                }
                return lst_Alarm;
            }
            else
                return null;

        }


        #endregion


        #region box报告  PDF
        Dictionary<string, string> batchinfo = new Dictionary<string, string>() {
                { "batchserial","批次号"},
                { "createtime","批次创建时间"},
                { "createuser","批次创建用户"},
                { "loadtime","料框装载时间"},
                { "errorcode","料框错误代码"},
                { "quenchmoveintime","淬火转移时间"}
            };
        string[] headTitle_en = new string[5] { "Zone Set", "Set Value", "OverHeat Set", "Upper Tolerance", "Lower Tolerance" };
        string[] headTitle_cn = new string[4] { "参数名称", "控制设定值", "参数名称", "控制设定值" };
        float[] headWidth = new float[4] { 189, 85, 189, 86 };
        int[] TimeSep = new int[16] { 5, 10, 15, 30, 45, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330, 360 };
        int TimeInterval = 0;
        int _errorcode = 0;

        /// <summary>
        /// 打印物料的报告，目前的功能尚需调整，暂不支持。20221104-cxf
        /// </summary>
        private void btn_Report_Click(object sender, EventArgs e)
        {
            //BoxDetail包括了当前的所有的信息
            //这里用来生成报告
            //进出设备的信息可以从表格中获取，甚至曲线显示的时间段也可以从表格中获取。
            if (grdProduct.SelectedRows == null) return;
            string _printBox = grdProduct.SelectedRows[0].Cells["box"].Value.ToString();
            string _printMark = grdProduct.SelectedRows[0].Cells["mark"].Value.ToString();
            string _printLoadtime = grdProduct.SelectedRows[0].Cells["loadtime"].Value.ToString();
            string _printBoxName = _printBox + _printMark.PadLeft(4, '0');
            StringBuilder sbfile = new StringBuilder(Application.StartupPath + @"\Batch_Reports\");
            sbfile.Append(_printBoxName).Append(".pdf");
            DataRow[] row = BoxDetail.Select(string.Format("box='{0}' and mark='{1}'", _printBox, _printMark));//在datatable中查找对应的行，用来后面的数据输出
            if (row.Length <= 0) return;
            fd_PDF pdf = new fd_PDF(PdfPageOrientation.Portrait);
            //生产信息（批次信息，产品信息，工艺信息）
            printPageBoxinfo(pdf, row[0]);
            //进出设备信息,从界面中的表格中获取信息
            PrintPageKeyTime(pdf, row[0]); 
            //警报信息（分几个主要设备，可以事先设置好设备的编号列表）
            Dictionary<string, int[]> _printAlarm = new Dictionary<string, int[]>()
            {
                { "1001", new int[2]{5,9 } },//加热炉
                { "3001", new int[2]{10,10 } },//淬火槽
                { "2001", new int[2]{0,2 } },//淬火槽
                { "4001", new int[2]{15,17 } },//回火炉
            };
            PrintPageAlarm(pdf, row[0], _printAlarm);

            //设备曲线（事先设置好设备字典和ZONEID数组，时间节点从界面中的表格中获取）
            List<DrawLineGroup> _printCurve = new List<DrawLineGroup>() {
                new DrawLineGroup(){EquipID="6001",SubText=" 温度曲线",KeyTimeStartIndex=3,KeyTimeEndIndex=4,ZoneID=new int[]{4,5} },
                new DrawLineGroup(){EquipID="1001",SubText=" 温度曲线",KeyTimeStartIndex=5,KeyTimeEndIndex=9,ZoneID=new int[]{ 10, 11, 12, 13 } },
                new DrawLineGroup(){EquipID="1001",SubText=" 碳势曲线",KeyTimeStartIndex=5,KeyTimeEndIndex=9,ZoneID=new int[]{ 14, 15, 16 },Unit="%C" },
                new DrawLineGroup(){EquipID="3001",SubText=" 温度曲线",KeyTimeStartIndex=10,KeyTimeEndIndex=10,ZoneID=new int[]{ 25 } },
                new DrawLineGroup(){EquipID="3001",SubText=" 搅拌速度曲线",KeyTimeStartIndex=10,KeyTimeEndIndex=10,ZoneID=new int[]{ 26,27 },Unit="rpm" },
                new DrawLineGroup(){EquipID="4001",SubText=" 温度曲线",KeyTimeStartIndex=15,KeyTimeEndIndex=17,ZoneID=new int[]{ 40, 41, 42 } }
            };

            PrintCurve(pdf, row[0], _printCurve);
            //保存PDF到文件
            pdf.SaveToPDF(sbfile.ToString());
            //卸载相关内容，释放内存
            foreach (PdfPageBase page in pdf.Doc.Pages)
                pdf.PageRemove(page);
            pdf.Doc = null;
            pdf = null;
            //——————————————————————————————显示pdf————————————————————————————
            ShowPDF(_printBoxName);
        }

        /// <summary>
        /// 打印产品信息页，批次信息 ,工艺信息
        /// </summary>
        private void printPageBoxinfo(fd_PDF pdf, DataRow row)
        {
            //绘制页面
            pdf.PagesAdd();
            PrintTitle(pdf, "Box " + row["box"] + row["mark"].ToString().PadLeft(4, '0'));
            PrintLog(pdf);
            //打印零件基本信息
            //PrintGroup(pdf, "Batch basic information", new RectangleF(pdf.Margin, 58, pdf.PageWidth - pdf.Margin * 2, 153));

            if (ProductInfoTitle == null || ProductInfoTitle.Rows.Count == 0) return;
            PrintGroup(pdf, "产品信息", new RectangleF(pdf.Margin, 58, pdf.PageWidth - pdf.Margin * 2, 34 + 24 * (ProductInfoTitle.Rows.Count + 1) / 2));
            float w = (pdf.PageWidth - pdf.Margin * 2 - 5 * 4) / 4;
            float top = 58 + 10;
            for (int i = 0; i < ProductInfoTitle.Rows.Count; i++)
            {
                int step = i % 2 == 0 ? 0 : 2;//列数
                top = top + (step == 0 ? 24 : 0);//每两项增加一行
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * step, top, w, 20), ProductInfoTitle.Rows[i]["infotitle"].ToString(), true);//打印的信息名称
                string v = row["info" + i] == null ? "" : row["info" + i].ToString();//信息的内容
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * (step + 1), top, w, 20), v, false);//打印内容
            }


            //打印批次生产信息

            top = top + 34;//增加间隔
            //PrintGroup(pdf, "批次信息", new RectangleF(pdf.Margin, top, pdf.PageWidth - pdf.Margin * 2, 24 + 24 * (BatchInfoTitle.Rows.Count + batchinfo.Count + 1) / 2));
            PrintGroup(pdf, "批次信息", new RectangleF(pdf.Margin, top, pdf.PageWidth - pdf.Margin * 2, 24 + 24 * ( batchinfo.Count + 1) / 2));
            top = top + 10;
            int j = 0;
            foreach (var item in batchinfo.Keys)
            {
                int step = j % 2 == 0 ? 0 : 2;//列数
                top = top + (step == 0 ? 24 : 0);//每两项增加一行
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * step, top, w, 20), batchinfo[item], true);
                string v = row[item] == null ? "" : row[item].ToString();//信息的内容
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * (step + 1), top, w, 20), v, false);
                j++;
            }

        ///批次信息暂时频闭
            //if (BatchInfoTitle == null || BatchInfoTitle.Rows.Count == 0) return;
            //for (int i = 0; i < BatchInfoTitle.Rows.Count; i++)
            //{
            //    int step = j % 2 == 0 ? 0 : 2;//列数
            //    top = top + (step == 0 ? 24 : 0);//每两项增加一行
            //    PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * step, top, w, 20), BatchInfoTitle.Rows[i]["infotitle"].ToString(), true);
            //    string v = row["info" + i + '1'] == null ? "" : row["info" + i + '1'].ToString();//信息的内容
            //    PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * (step + 1), top, w, 20), v, false);
            //    j++;
            //}


            //打印工艺信息
            if (row["productversion"] == null) return;
            DataTable programinfo = DBOperate.GetProductProgram(row["productversion"].ToString());
            if (programinfo == null || programinfo.Rows.Count == 0) return;
            top = top + 34;//增加间隔
            int lines = (800 - (int)top - 55) / 22;
            PrintGroup(pdf, "[" + row["info0"] + "] 工艺参数" + ((lstzone.Count > lines * 2) ? "(1/2)" : ""), new RectangleF(pdf.Margin, top, pdf.PageWidth - pdf.Margin * 2, (lines + 1) * 22 + 25 + 4 + 6));

            top = top + 33;
            for (int i = 0; i < 4; i++)
            {
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * i, top, w, 20), headTitle_cn[i], true);
            }
            for (int i = 0; i < lstzone.Count && i < lines * 2; i++)
            {
                int step = i % 2 == 0 ? 0 : 2;//列数
                top = top + (step == 0 ? 22 : 0);//每两项增加一行
                string v = "-";
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * step, top, w, 20), lstzone[i].ZoneName + " " + lstzone[i].Unit, true);
                if (lstzone[i].sv != null && programinfo.Columns.Contains(lstzone[i].ID.ToString()))
                    v = programinfo.Rows[0][lstzone[i].ID.ToString()].ToString();
                PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * (step + 1), top, w, 20), v, false);
            }
            if (lstzone.Count > lines * 2)//打印第二页工艺参数内容
            {
                pdf.PagesAdd();
                PrintTitle(pdf, "Box " + row["box"] + row["mark"].ToString().PadLeft(4, '0'));
                PrintLog(pdf);
                top = 58;
                int nextlines = (800 - (int)top - 55) / 22;
                PrintGroup(pdf, "[" + row["info0"] + "] 工艺参数" + ((lstzone.Count > lines * 2) ? "(2/2)" : ""), new RectangleF(pdf.Margin, top, pdf.PageWidth - pdf.Margin * 2, (nextlines + 1) * 22 + 25 + 4 + 6));

                top = top + 33;
                for (int i = 0; i < 4; i++)
                {
                    PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * i, top, w, 20), headTitle_cn[i], true);
                }
                for (int i = lines * 2; i < lstzone.Count && i < (nextlines + lines) * 2; i++)
                {
                    int step = i % 2 == 0 ? 0 : 2;//列数
                    top = top + (step == 0 ? 22 : 0);//每两项增加一行
                    string v = "-";
                    PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * step, top, w, 20), lstzone[i].ZoneName, true);
                    if (lstzone[i].sv != null && programinfo.Columns.Contains(lstzone[i].ID.ToString()))
                        v = programinfo.Rows[0][lstzone[i].ID.ToString()].ToString();
                    PrintContent(pdf, new RectangleF(pdf.Margin + 4 + (w + 4) * (step + 1), top, w, 20), v, false);
                }
            }
        }

        /// <summary>
        /// 打印物料进出各个设备的时间节点
        /// </summary>
        private void PrintPageKeyTime(fd_PDF pdf, DataRow row)
        {
            //string[] _headTitle = new string[5] { "Index", "Equip Zone", "Move in time", "Move out time", "Stay" };
            string[] _headTitle = new string[5] { "序号", "设备分区", "进入时间", "移出时间", "停留时间" };
            float[] _headWidth = new float[5] { 55, 130, 140, 140, 84 };
            //绘制页面
            pdf.PagesAdd();
            PrintTitle(pdf, "Box " + row["box"] + row["mark"].ToString().PadLeft(4, '0'));
            PrintLog(pdf);
            //PrintGroup(pdf, "Batch Actions", new RectangleF(pdf.Margin, 58, pdf.PageWidth - pdf.Margin * 2, 762));
            PrintGroup(pdf, "料框转移时间节点", new RectangleF(pdf.Margin, 58, pdf.PageWidth - pdf.Margin * 2, 762));
            float w = 4f;
            for (int i = 0; i < 5; i++)
            {
                PrintContent(pdf, new RectangleF(pdf.Margin + w, 58 + 25 + 8, _headWidth[i] - 2, 20), _headTitle[i], true);
                w += _headWidth[i];
            }

            for (int i = 0; i < lvKeyTime.Items.Count; i++)
            {
                w = 4f;
                for (int j = 0; j < 5; j++)
                {
                    PrintContent(pdf, new RectangleF(pdf.Margin + w, 58 + 25 + 30 + i * 22, _headWidth[j] - 2, 20), lvKeyTime.Items[i].SubItems[j].Text, false);
                    w += _headWidth[j];
                }
            }
        }
        /// <summary>
        /// 打印列表中各个设备报警的内容
        /// </summary>
        /// <param name="_printAlarm">打印的相关设置</param>
        private void PrintPageAlarm(fd_PDF pdf, DataRow row, Dictionary<string, int[]> _printAlarm)
        {
            string[] _headTitle = new string[4] { "警报名称", "发生时间", "复位时间", "警报等级" };
            string[] _columTitle = new string[4] { "alarmname", "occurtime", "resettime", "level" };
            float[] _headWidth = new float[4] { 240, 130, 130, 49 };

            List<PrintAlarmGroup> algroup = new List<PrintAlarmGroup>();
            DateTime a;
            DateTime b;
            int pagerows = 32;
            foreach (var item in _printAlarm.Keys)
            {
                if (DateTime.TryParse(lvKeyTime.Items[_printAlarm[item][0]].SubItems[2].Text, out a) && DateTime.TryParse(lvKeyTime.Items[_printAlarm[item][1]].SubItems[3].Text, out b))
                    algroup.Add(new PrintAlarmGroup(item, a, b));
            }
            //每个设备报警分一组，并且开头按照分页的来

            for (int i = 0; i < algroup.Count; i++)
            {
                DataTable dt = DBOperate.GetAlarmHistory(algroup[i].EquipID, algroup[i].StartTime, algroup[i].EndTime);
                if (dt == null || dt.Rows.Count == 0) continue;
                //统计报警的行数。并决定分页情况
                List<DataRow> rows = GetAlarmDetail(dt);
                int totalpages = (rows.Count - 1) / pagerows + 1;//每页32行
                for (int pageindex = 0; pageindex < totalpages; pageindex++)
                {
                    float top = 58f;
                    //绘制页面
                    pdf.PagesAdd();
                    PrintTitle(pdf, "Box " + row["box"] + row["mark"].ToString().PadLeft(4, '0'));
                    PrintLog(pdf);
                    //打印表头
                    PrintGroup(pdf, QueryForms.fmquery.netline.Equip[algroup[i].EquipID].EquipName + " 相关警报", new RectangleF(pdf.Margin, top, pdf.PageWidth - pdf.Margin * 2, 762));
                    float w = 4f;
                    top = top + 25 + 8;
                    for (int j = 0; j < 4; j++)
                    {
                        PrintContent(pdf, new RectangleF(pdf.Margin + w, top, _headWidth[j] - 2, 20), _headTitle[j], true);
                        w += _headWidth[j];
                    }
                    top = top + 22;
                    //打印数据
                    for (int rowindex = pageindex * pagerows; rowindex < rows.Count && rowindex < (pageindex + 1) * pagerows; rowindex++)
                    {
                        w = 4f;
                        for (int j = 0; j < 4; j++)
                        {
                            PrintContent(pdf, new RectangleF(pdf.Margin + w, top, _headWidth[j] - 2, 20), rows[rowindex][_columTitle[j]].ToString(), rowindex % 2 != 0);
                            w += _headWidth[j];
                        }
                        top = top + 22;
                    }
                }
            }
        }
        /// <summary>
        /// 获取一个报警的详细信息列表供打印用
        /// </summary>
        /// <param name="AlarmDatatable">数据库中查询的相关设备的报警详细信息DATATABLE</param>
        /// <returns></returns>
        private List<DataRow> GetAlarmDetail(DataTable AlarmDatatable)
        {
            DataTable dt = new DataTable("alarm");
            List<DataRow> lstrows = new List<DataRow>();
            dt.Columns.AddRange(new DataColumn[] { new DataColumn("alarmname"), new DataColumn("occurtime"), new DataColumn("resettime"), new DataColumn("level"), new DataColumn("id"), });

            for (int i = AlarmDatatable.Rows.Count - 1; i >= 0; i--)
            {
                if (AlarmDatatable.Rows[i]["AlarmActive"].ToString() == "0")
                {
                    DataRow rw = dt.NewRow();
                    rw["alarmname"] = AlarmDatatable.Rows[i]["AlarmName"];
                    rw["level"] = AlarmDatatable.Rows[i]["AlarmLevel"];
                    rw["resettime"] = AlarmDatatable.Rows[i]["SaveTime"];
                    rw["id"] = AlarmDatatable.Rows[i]["alID"];
                    lstrows.Add(rw);
                    //lst_Alarm.Items.Add(new ListViewItem(new string[] { (lst_Alarm.Items.Count + 1).ToString(), AlarmDatatable.Rows[i]["AlarmName"].ToString(), AlarmDatatable.Rows[i]["AlarmLevel"].ToString(), "", AlarmDatatable.Rows[i]["SaveTime"].ToString() }));//最后是报警等级，最后修改
                }
                else
                {
                    //1这里加载数据，对数据进行重组
                    int lastindex = -10;
                    for (int k = lstrows.Count - 1; k >= 0; k--)
                    {
                        if (AlarmDatatable.Rows[i]["alid"].ToString() == lstrows[k]["id"].ToString() && lstrows[k]["occurtime"].ToString() == "")
                        {
                            lstrows[k]["occurtime"] = AlarmDatatable.Rows[i]["SaveTime"];
                            lastindex = k;
                            break;
                        }
                    }
                    if (lastindex == -10)
                    {
                        DataRow rw = dt.NewRow();
                        rw["alarmname"] = AlarmDatatable.Rows[i]["AlarmName"];
                        rw["level"] = AlarmDatatable.Rows[i]["AlarmLevel"];
                        rw["occurtime"] = AlarmDatatable.Rows[i]["SaveTime"];
                        rw["id"] = AlarmDatatable.Rows[i]["alID"];
                        lstrows.Add(rw);
                        //lst_Alarm.Items.Add(new ListViewItem(new string[] { (lst_Alarm.Items.Count + 1).ToString(), AlarmDatatable.Rows[i]["AlarmName"].ToString(), AlarmDatatable.Rows[i]["AlarmLevel"].ToString(), AlarmDatatable.Rows[i]["SaveTime"].ToString(), "" }));
                    }
                }
            }
            return lstrows;
        }
        private void PrintCurve(fd_PDF pdf, DataRow row, List<DrawLineGroup> _printCurve)
        {
            for (int i = 0; i < _printCurve.Count; i++)
            {
                pdf.PagesAdd();
                PrintTitle(pdf, "Box " + row["box"] + row["mark"].ToString().PadLeft(4, '0'));
                PrintLog(pdf);
                PrintGroup(pdf, QueryForms.fmquery.netline.Equip[_printCurve[i].EquipID].EquipName + _printCurve[i].SubText, new RectangleF(pdf.Margin, 58, pdf.PageWidth - pdf.Margin * 2, pdf.PageHeight - pdf.Margin - 58));

                if (DateTime.TryParse(lvKeyTime.Items[_printCurve[i].KeyTimeStartIndex].SubItems[2].Text, out DateTime a) && DateTime.TryParse(lvKeyTime.Items[_printCurve[i].KeyTimeEndIndex].SubItems[3].Text, out DateTime b))
                {
                    _printCurve[i].StartTime = a;
                    _printCurve[i].EndTime = b;
                    DrawCurve(pdf, _printCurve[i], new RectangleF(pdf.Margin + 4f, 58 + 25 + 8, pdf.PageWidth - pdf.Margin * 2 - 8, pdf.PageHeight - pdf.Margin - 58 - 25 - 12));
                }
            }

        }
        private void DrawCurve(fd_PDF pdf, DrawLineGroup linegroup, RectangleF rect)
        {
            Dictionary<int, float[]> data = new Dictionary<int, float[]>();
            int totalminutes = (int)linegroup.EndTime.Subtract(linegroup.StartTime).TotalMinutes + 1;

            DataTable dt = DBOperate.GetParameterData(linegroup.StartTime, linegroup.EndTime);
            if (dt == null || dt.Rows.Count == 0) return;
            //初始化数据区data的数组
            for (int j = 0; j < linegroup.ZoneID.Length; j++)
            {
                if (QueryForms.fmquery.netline.zone[linegroup.ZoneID[j]].pv != null)
                {
                    data[QueryForms.fmquery.netline.zone[linegroup.ZoneID[j]].pv.ID] = new float[totalminutes];
                }
                //如果需要SV就可以在这里添加sv的id了
            }
            //获取数据
            DateTime middletime;
            for (int j = 0; j < dt.Rows.Count; j++)
            {
                if (DateTime.TryParse(dt.Rows[j]["savetime"].ToString(), out middletime))
                {
                    int diff = (int)middletime.Subtract(linegroup.StartTime).TotalMinutes;
                    foreach (var item in data.Keys)
                    {
                        if (float.TryParse(dt.Rows[j][item.ToString()].ToString(), out float f))
                        {
                            data[item][diff] = f;
                            if (f > linegroup.AsixMax) linegroup.AsixMax = f;
                            if (f < linegroup.AsixMin) linegroup.AsixMin = f;
                        }
                    }
                }
            }
            if (linegroup.Unit != "%C")
            {
                linegroup.AsixMax = ((int)(linegroup.AsixMax / 10) + 1) * 10;
                linegroup.AsixMin = ((int)(linegroup.AsixMin / 10)) * 10;
            }
            else
            {
                linegroup.AsixMax = ((int)(linegroup.AsixMax * 10f) + 1) / 10f;
                linegroup.AsixMin = ((int)(linegroup.AsixMin * 10f)) / 10f;
            }

            if (linegroup.AsixMax - linegroup.AsixMin <= 0) return;
            //画图
            Bitmap bm = new Bitmap((int)rect.Height, (int)rect.Width);//横过来画
            //坐标轴
            Drawbg(bm, linegroup);
            //画线
            DrawLines(bm, linegroup, data);
            //打印到PDF上
            bm.RotateFlip(RotateFlipType.Rotate90FlipNone);
            Image img = bm;
            pdf.DrawImage(img, rect);
        }
        private void Drawbg(Bitmap bm, DrawLineGroup linegroup)
        {

            if (bm.Width == 0 || bm.Height == 0) return;
            float totalminutes = (float)linegroup.EndTime.Subtract(linegroup.StartTime).TotalMinutes + 1;
            TimeInterval = (int)linegroup.EndTime.Subtract(linegroup.StartTime).TotalMinutes / 9;
            for (int i = 0; i < TimeSep.Length; i++)
            {
                if (TimeInterval <= TimeSep[i])
                {
                    TimeInterval = TimeSep[i];
                    break;
                }
            }
            int HourLines = (int)totalminutes / TimeInterval;

            float margin = 40;
            float h = bm.Height - 100;
            float w = bm.Width;
            float ww = w * (TimeInterval / totalminutes);
            //画横向的线
            float smallDiv = h / 50;
            float bigDiv = smallDiv * 10;
            Graphics g = Graphics.FromImage(bm);
            g.Clear(Color.White);
            Pen p = new Pen(Color.Gray, 1);
            SolidBrush brush = new SolidBrush(Color.Black);
            string s;
            for (int i = 0; i < 5; i++)
            {
                p.Color = Color.DarkGray;
                g.DrawLine(p, margin - 5, i * bigDiv, w, i * bigDiv);
                s = (linegroup.AsixMin + (5 - i) * ((linegroup.AsixMax - linegroup.AsixMin) / 5)).ToString();
                g.DrawString(s, this.Font, brush, new PointF(margin - g.MeasureString(s, this.Font).Width, i * bigDiv));

                p.Color = Color.LightGray;
                for (int j = 1; j < 10; j++)
                {
                    g.DrawLine(p, margin, i * bigDiv + j * smallDiv, w, i * bigDiv + j * smallDiv);
                }
            }
            p.Color = Color.DarkGray;
            g.DrawLine(p, margin - 5, h, w, h);
            s = linegroup.AsixMin.ToString();
            g.DrawString(s, this.Font, brush, new PointF(margin - g.MeasureString(s, this.Font).Width, h));
            g.DrawString(linegroup.Unit, this.Font, brush, new PointF(margin - g.MeasureString(linegroup.Unit, this.Font).Width - 10f, 20));

            //画纵向的线
            for (int i = 0; i <= HourLines; i++)
            {
                p.Color = Color.DarkGray;
                g.DrawLine(p, new PointF(margin + ww * i, 0), new PointF(margin + ww * i, h));
            }

            g.DrawLine(p, w - 1, 0, w - 1, h);//最后的那条线
            g.DrawString(linegroup.StartTime.ToString("yyyy-MM-dd HH:mm:00"), this.Font, brush, new PointF(margin, h + 10));
            s = linegroup.EndTime.ToString("yyyy-MM-dd HH:mm:00");
            g.DrawString(s, this.Font, brush, new PointF(bm.Width - g.MeasureString(s, this.Font).Width - margin, h + 10));
            s = TimeInterval + " Minutes/div";
            g.DrawString(s, this.Font, brush, new PointF((bm.Width - g.MeasureString(s, this.Font).Width - margin) / 2, h + 10));
        }
        private void DrawLines(Bitmap bm, DrawLineGroup linegroup, Dictionary<int, float[]> data)
        {
            if (bm.Width == 0 || bm.Height == 0) return;
            float totalminutes = (float)linegroup.EndTime.Subtract(linegroup.StartTime).TotalMinutes + 1;
            float margin = 40;
            float h = bm.Height - 100;
            float w = bm.Width - margin;
            float timdiff = w / totalminutes;
            int posindex = 0;
            float icondiff = w / 4f;

            for (int k = 0; k < linegroup.ZoneID.Length; k++)
            {
                if (QueryForms.fmquery.netline.zone[linegroup.ZoneID[k]].pv == null) continue;
                int ItemIndex = QueryForms.fmquery.netline.zone[linegroup.ZoneID[k]].pv.ID;
                if (!data.ContainsKey(ItemIndex) || !QueryForms.fmquery.netline.LineSetting.ContainsKey(ItemIndex)) continue;
                Pen p = new Pen(QueryForms.fmquery.netline.LineSetting[ItemIndex].CurveColor, 2);
                Graphics g = Graphics.FromImage(bm);
                //画线
                float x0, y0, x1, y1;
                x0 = margin;
                y0 = h * (linegroup.AsixMax - data[ItemIndex][0]) / (linegroup.AsixMax - linegroup.AsixMin);
                for (int j = 1; j < data[ItemIndex].Length && j < totalminutes; j++)
                {
                    y1 = h * (linegroup.AsixMax - data[ItemIndex][j]) / (linegroup.AsixMax - linegroup.AsixMin);
                    x1 = margin + j * timdiff;
                    if (data[ItemIndex][j] * data[ItemIndex][j - 1] != 0)
                    {
                        g.DrawLine(p, x0, y0, x1, y1);
                    }
                    y0 = y1;
                    x0 = x1;
                }
                //图示
                SolidBrush brush = new SolidBrush(QueryForms.fmquery.netline.LineSetting[ItemIndex].CurveColor);
                g.FillRectangle(brush, margin + (posindex % 4) * icondiff, 30 + h + (posindex / 4) * 20, 10, 10);
                brush.Color = Color.Black;
                g.DrawString(QueryForms.fmquery.netline.zone[linegroup.ZoneID[k]].ZoneName, this.Font, brush, margin + 15 + (posindex % 4) * icondiff, 30 + h + (posindex / 4) * 20);
                posindex++;
            }

        }
        #endregion


        #region public print functions
        private void ShowPDF(string boxname)
        {
            string file = Application.StartupPath + @"\Batch_Reports\" + boxname + ".pdf";
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = file;
            p.StartInfo.UseShellExecute = true;
            p.Start();
        }

        private void PrintLog(Graphics g)
        {
            //打印LOG
            if (!File.Exists(Application.StartupPath + @"\logo.png")) return;
            Image img = Image.FromFile(Application.StartupPath + @"\logo.png");
            g.DrawImage(img, new RectangleF(pageSize.Width - img.Width * 0.6f - pageMargin, -5f + pageMargin, img.Width * 0.6f, img.Height * 0.6f));

        }
        private void PrintLog(fd_PDF pdf)
        {
            //打印LOG
            if (!File.Exists(Application.StartupPath + @"\logo.png")) return;
            Image img = Image.FromFile(Application.StartupPath + @"\logo.png");
            pdf.DrawImage(img, new RectangleF(pdf.PageWidth - img.Width * 0.6f - pdf.Margin, -5 + pdf.Margin, img.Width * 0.6f, img.Height * 0.6f));
        }

        private void PrintTitle(fd_PDF pdf, string title)
        {
            PdfTrueTypeFont fontTitle = new PdfTrueTypeFont(new Font("微软雅黑", 18f, FontStyle.Bold), true);
            PdfSolidBrush brush = pdf.BrushColor(Color.Black);
            pdf.DrawString(title, fontTitle, brush, new PointF(pdf.Margin, pdf.Margin + 5));
        }

        private float PrintGroup(Graphics g, string groupName, RectangleF rectangle)
        {
            Font font = new Font("微软雅黑", 14f, FontStyle.Regular);
            Brush brush = new SolidBrush(Color.WhiteSmoke);
            SizeF sf = g.MeasureString(groupName, font);
            Pen pen = new Pen(Color.LightGray);
           // g.DrawRectangle(pen, rectangle.Left,rectangle.Top, rectangle.Width ,rectangle.Height );
            g.FillRectangle( brush, new RectangleF(rectangle.Left, rectangle.Top, rectangle.Width, sf.Height*1.4f));
            brush = new SolidBrush(Color.Black);
            g.DrawString(groupName, font, brush, new PointF(rectangle.Left + sf.Height*0.2f, rectangle.Top + sf.Height * 0.2f));
            return rectangle.Top+ sf.Height * 1.6f;
        }

        private void PrintGroup(fd_PDF pdf, string groupName, RectangleF rectangle)
        {
            PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("微软雅黑", 14f, FontStyle.Regular), true);
            PdfSolidBrush brush = pdf.BrushColor(Color.WhiteSmoke);
            PdfPen pen = pdf.PenColor(Color.LightGray);
            pdf.DrawRectangle(pen, rectangle);
            pdf.DrawRectangle(pen, brush, new RectangleF(rectangle.Left + 4, rectangle.Top + 4, rectangle.Width - 8, 25));
            brush = pdf.BrushColor(Color.Black);
            pdf.DrawString(groupName, font, brush, new PointF(rectangle.Left + 8, rectangle.Top + 6.5f));
        }
        private float PrintContent(Graphics g, RectangleF rectangle, string content, bool istitle, PdfTextAlignment align = PdfTextAlignment.Left)
        {
            return PrintContent(g, rectangle, content, 10f, Color.DarkSlateGray, Color.WhiteSmoke, istitle, align);
        }
        private void PrintContent(fd_PDF pdf, RectangleF rectangle, string content, bool istitle, PdfTextAlignment align = PdfTextAlignment.Left)
        {
            PrintContent(pdf, rectangle, content, 12f, Color.DarkSlateGray, Color.WhiteSmoke, istitle, align);
        }
        private void PrintContent(Graphics g, RectangleF rectangle, string content, float fontsize, PdfTextAlignment align = PdfTextAlignment.Left, bool hasboard = true)
        {
            Brush txtbrush =new SolidBrush(Color.DarkSlateGray);
            Brush bgbrush = new  SolidBrush(Color.WhiteSmoke);
            Font font = new Font("微软雅黑", fontsize, FontStyle.Regular);
            Pen penboard = new Pen(Color.LightGray);
            if (hasboard) g.DrawRectangle(penboard, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height);
            g.DrawString(content, font, txtbrush, rectangle);
        }
        private void PrintContent(fd_PDF pdf, RectangleF rectangle, string content, float fontsize, PdfTextAlignment align = PdfTextAlignment.Left, bool hasboard = true)
        {
            PdfSolidBrush txtbrush = pdf.BrushColor(Color.DarkSlateGray);
            PdfSolidBrush bgbrush = pdf.BrushColor(Color.WhiteSmoke);
            PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("微软雅黑", fontsize, FontStyle.Regular), true);
            PdfPen penboard = pdf.PenColor(Color.LightGray);
            if (hasboard) pdf.DrawRectangle(penboard, bgbrush, rectangle);
            PdfPen pentext = pdf.PenColor(Color.DarkSlateGray);
            pdf.DrawString(content, font, txtbrush, rectangle, null, align);
        }
        private void PrintContent(Graphics g, RectangleF rectangle, string content, float fontsize, bool istitle)
        {
            PrintContent(g, rectangle, content, fontsize, Color.DarkSlateGray, Color.WhiteSmoke, istitle);
        }
        private void PrintContent(fd_PDF pdf, RectangleF rectangle, string content, float fontsize, bool istitle)
        {
            PrintContent(pdf, rectangle, content, fontsize, Color.DarkSlateGray, Color.WhiteSmoke, istitle);
        }


        private float PrintProContent(Graphics g, RectangleF rectangle, string content, float fontsize, Color txtColor, Color bgColor, bool istitle)
        {
            Brush txtbrush = new SolidBrush(txtColor);
            Brush bgbrush = new SolidBrush(bgColor);
            Font font = new Font("微软雅黑", fontsize, FontStyle.Regular);
            SizeF sf = g.MeasureString(content + " ", font);
            Pen pen = new Pen(Color.LightGray);
            if (istitle)
            {
                g.FillRectangle(bgbrush, rectangle.Left, rectangle.Top, rectangle.Width, sf.Height * 1.2f);
            }
            else
            {
                g.DrawRectangle(pen, rectangle.Left, rectangle.Top, rectangle.Width, sf.Height * 1.2f);
            }
            g.DrawString(content, font, txtbrush, new PointF(rectangle.Left + sf.Height * 0.1f, rectangle.Top + sf.Height * 0.1f));

            return rectangle.Top + sf.Height * 1.3f;

        }
        private float PrintContent(Graphics g, RectangleF rectangle, string content, float fontsize, Color txtColor, Color bgColor, bool istitle, PdfTextAlignment align = PdfTextAlignment.Left)
        {
            Brush txtbrush = new SolidBrush(txtColor);
            Brush bgbrush = new SolidBrush(bgColor);
            Font font = new Font("微软雅黑", fontsize, FontStyle.Regular);
            SizeF sf = g.MeasureString(content+" ", font);
            Pen pen = new Pen(Color.LightGray);
            if (istitle)
            {
                g.FillRectangle(bgbrush, rectangle.Left, rectangle.Top, rectangle.Width , sf.Height *1.4f);
            }
            else
            {
                g.DrawRectangle(pen, rectangle.Left, rectangle.Top, rectangle.Width, sf.Height * 1.4f);
            }
            g.DrawString(content, font, txtbrush, new PointF(rectangle.Left + sf.Height*0.2f, rectangle.Top + sf.Height*0.2f));

            return rectangle.Top + sf.Height * 1.6f;

        }
        private void PrintContent(fd_PDF pdf, RectangleF rectangle, string content, float fontsize, Color txtColor, Color bgColor, bool istitle, PdfTextAlignment align = PdfTextAlignment.Left)
        {
            PdfSolidBrush txtbrush = pdf.BrushColor(txtColor);
            PdfSolidBrush bgbrush = pdf.BrushColor(bgColor);
            PdfTrueTypeFont font = new PdfTrueTypeFont(new Font("微软雅黑", fontsize, FontStyle.Regular), true);
            PdfPen pen = pdf.PenColor(Color.LightGray);
            if (istitle)
            {
                pdf.DrawRectangle(pen, bgbrush, rectangle);
            }
            else
            {
                pdf.DrawRectangle(pen, rectangle);
            }
            float div = (rectangle.Height - fontsize) / 2 - 2;
            pdf.DrawString(content, font, txtbrush, new PointF(rectangle.Left + 4, rectangle.Top + div));
        }


        #endregion

        private void btn_Close_Click(object sender, EventArgs e)
        {
            pnl_Print.Visible = false;
        }

        private void btn_QueryBoxWeight_Click(object sender, EventArgs e)
        {
            Form_QueryBoxWeight fmweight = new Form_QueryBoxWeight();
            fmweight.ShowDialog();
        }
    }

    #region Other Class
    public class PrintAlarmGroup
    {
        public DateTime StartTime { get; }
        public DateTime EndTime { get; }
        public string EquipID { get; } = "";
        public PrintAlarmGroup(string _equipID, DateTime _startTime, DateTime _endTime)
        {
            EquipID = _equipID;
            StartTime = _startTime;
            EndTime = _endTime;
        }
    }

    public class DrawLineGroup
    {
        public string EquipID { get; set; }
        public string SubText { get; set; }
        public int KeyTimeStartIndex { get; set; }
        public int KeyTimeEndIndex { get; set; }
        public int[] ZoneID { get; set; }
        public float AsixMax { get; set; } = -10000f;
        public float AsixMin { get; set; } = 100000f;
        public string Unit { get; set; } = "℃";
        public DateTime StartTime { get; set; }
        public DateTime EndTime { get; set; }
    }
    #endregion
}
